package com.jsyso.jsyso.spring;

import javax.sql.DataSource;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

import com.jsyso.jsyso.db.Db;
import com.jsyso.jsyso.db.id.MySqlSequence;
import com.jsyso.jsyso.exception.DbException;

/**
 * MySql序列生成器
 * @author janjan, xujian_jason@163.com
 *
 */
public class MySqlSequenceFactoryBean implements FactoryBean<MySqlSequence>, InitializingBean {

	// 序列生成器
	private MySqlSequence sequence;
	// 生成器数据源集合
	private DataSource[] dataSources;
	// Db数据库对象
	private Db db;
	
	protected MySqlSequence buildMySqlSequence() {
		if((dataSources == null || dataSources.length == 0) && db == null) {
			throw new DbException("请在spring.xml中<bean class='MySqlSequenceFactoryBean'>注入dataSources或者db属性");
		}
		NamedParameterJdbcOperations[] jdbcs = null;
		// 大多数情况：只有一个数据源，并且生成器是在主库中
		if(this.db != null) {
			jdbcs = new NamedParameterJdbcOperations[1];
			// 序列生成器使用db的master库
			jdbcs[0] = this.db.getMaster();
		}else {
			// 如果生成器在其他库中，使用多数据源配置
			jdbcs = new NamedParameterJdbcOperations[this.dataSources.length];
			int i=0, length = this.dataSources.length;
			for(; i<length; ++i) {
				DataSource dataSource = this.dataSources[i];
				jdbcs[i] = new NamedParameterJdbcTemplate(dataSource);
			}
		}
		// 创建序列生成器
		MySqlSequence sqlSequence = new MySqlSequence();
		sqlSequence.setJdbcs(jdbcs);
		return sqlSequence;
	}
	
	@Override
	public void afterPropertiesSet() throws Exception {
		this.sequence = this.buildMySqlSequence();
	}

	@Override
	public MySqlSequence getObject() throws Exception {
		if(this.sequence == null) {
			afterPropertiesSet();
		}
		return this.sequence;
	}

	@Override
	public Class<?> getObjectType() {
		return this.sequence == null ? MySqlSequence.class : this.sequence.getClass();
	}

	@Override
	public boolean isSingleton() {
		return true;
	}
	
	public void setDb(Db db) {
		this.db = db;
	}
	
	public void setDataSources(DataSource[] dataSources) {
		this.dataSources = dataSources;
	}
}
